package com.wkbb.basic.filter;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wkbb.common.config.ServiceConfig;
import com.wkbb.common.constants.ErrorCode;
import com.wkbb.common.constants.RedisKeyConstant;
import com.wkbb.common.dto.ResultDTO;
import com.wkbb.common.dto.basic.RoleTypeDto;
import com.wkbb.common.dto.basic.RoleTypeJsonDto;
import com.wkbb.common.dto.basic.UserDto;
import com.wkbb.common.redis.RedisTemplateUtil;
import com.wkbb.common.redis.UserRedisTemplateUtil;
import com.wkbb.common.utils.SpringUtil;
import com.wkbb.common.utils.StringUtil;
import com.wkbb.common.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 用户权限校验过滤器，针对URL进行权限校验
 */
@Slf4j
public class TokenFilter implements Filter {
	
	  @Autowired
	  private RedisTemplateUtil redisTemplateUtil;

    // 不需要校验权限的URL  容器启动 过滤器初始化时会先加载web.xml文件中配置的不需要校验权限的URL
    private List<String> noFilterEndWithList = new ArrayList<String>();
    private List<String> noFilterWithList = new ArrayList<String>();

    // 访问的工程名  同上，假如是访问localhost:8080/user   得到的是/user
    String contextPath = null;

    // 销毁
    @Override
    public void destroy() {

    }

    // 过滤执行的逻辑代码
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String path = httpServletRequest.getServletPath();

        Boolean result = true;

        //过滤
        if (isVerification(path)) {
            result = checkToken(servletRequest);
        }

        if (!result) {
            HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
            httpResponse.setCharacterEncoding("UTF-8");
            httpResponse.setContentType("application/json; charset=utf-8");
            httpResponse.setStatus(HttpServletResponse.SC_OK);

            ResultDTO resultDTO = new ResultDTO(ErrorCode.USER_NOT_AUTH);
            ObjectMapper mapper = new ObjectMapper();
            httpResponse.getWriter().write(mapper.writeValueAsString(resultDTO));
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }


    /**
     * isVerification(判断指定的url是否需要验证，默认是需要验证的) (这里描述这个方法适用条件 – 可选)
     *
     * @param path
     * @return false代表不用验证 true 代表需要进行验证 Boolean
     * @throws
     */
    private Boolean isVerification(String path) {

        //js、html、css、图片文件等直接跳过
        if (path.indexOf(".") > -1) {
            return false;
        }

        if ("/".equals(path)) { // 防止无限重定向
            return false;
        }

        for (int i = 0; i < noFilterEndWithList.size(); i++) {
            if (path.endsWith(noFilterEndWithList.get(i))) {
                return false;
            }
        }

        for (int i = 0; i < noFilterWithList.size(); i++) {
            if (path.indexOf(noFilterWithList.get(i)) > -1) {
                return false;
            }
        }

        return true;

    }


    /**
     * 服务器启动是过滤器初始化的参数  加载不需要验证的url
     */
    @Override
    public void init(FilterConfig config) throws ServletException {

        noFilterEndWithList.add("/index");
        noFilterEndWithList.add("/login");
        noFilterEndWithList.add("/loginByPwd");
        noFilterEndWithList.add("/getLoginToken");
        noFilterEndWithList.add("/getOpenMenuTreeList");
        noFilterEndWithList.add("/exportStudentInfoExcel");
        noFilterEndWithList.add("/exportFamilyInfoExcel");
        noFilterEndWithList.add("/exportTeacherExcel");

        noFilterWithList.add("/open/");
        noFilterWithList.add("swagger");
        noFilterWithList.add("/api-docs");

        // 获取工程名
        contextPath = config.getServletContext().getContextPath();
    }

    private Boolean checkToken(ServletRequest servletRequest) {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String path = request.getServletPath();

        // 跳过 OPTIONS 请求（CORS 预检请求）
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            log.info("*****TokenFilter 跳过OPTIONS请求*****");
            return true;
        }

        try {
            log.info("*****TokenFilter checkToken*****");

            // 从容器中获取redisTemplate  bean
            ApplicationContext applicationContext = SpringUtil.getApplicationContext();
            RedisTemplateUtil redisTemplateUtil = applicationContext.getBean(UserRedisTemplateUtil.class);
            ServiceConfig serviceConfig = applicationContext.getBean(ServiceConfig.class);

            String token = request.getHeader("token");
            log.info("*****TokenFilter token:{}*****",token);
            String userJsonStr = redisTemplateUtil.getJSON(RedisKeyConstant.WKBB_BASIC_USER_BACK + RedisKeyConstant.WKBB_BASIC_USER_BACK_TOKEN + token);
            log.info("********AuthorityFilter.checkToken********userJsonStr:{}", userJsonStr);
            if (StringUtil.isEmpty(userJsonStr)) {
                return false;
            }

            //生成token值
            TokenUtil tokenUtil = new TokenUtil(serviceConfig.getTokenSecretKey(), serviceConfig.getTokenAlgorithm());
            UserDto userDto = JSONObject.parseObject(userJsonStr, UserDto.class);

            // 验证token是否经过篡改，并防止token伪造
            JSONArray userRoleTypeJsonArray = (JSONArray) userDto.getRoleType();

            //如果数据格式有问题，则抛出
            if(userRoleTypeJsonArray.size()==0)
            {
                return false;
            }

            //校验
            for (int i = 0; i < userRoleTypeJsonArray.size(); i++) {
                JSONObject roleTypeObject = userRoleTypeJsonArray.getJSONObject(i);

                RoleTypeJsonDto roleTypeJsonDto = JSONObject.parseObject(roleTypeObject.toJSONString(),RoleTypeJsonDto.class);
                if(null!=roleTypeJsonDto) {

                    List<RoleTypeDto> roleTypes = roleTypeJsonDto.getRoleTypes();
                    for (RoleTypeDto roleTypeDto : roleTypes) {

                        //组装TOKEN KEY
                        String key = roleTypeJsonDto.getAccountId() + "-" + roleTypeJsonDto.getOrgId() + "-" + userDto.getId();
                        String tokenV = tokenUtil.getToken(key);

                        //比较，匹配到，则说明token有效
                        if(token.equals(tokenV))
                        {
                            return true;
                        }

                    }
                }

            }

        } catch (Exception e) {
            log.error("----------token错误:{}",e.getMessage());
            return false;
        }

        return true;
    }

}
